package com.itheima.controller;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.itheima.bean.Category;
import com.itheima.bean.Dish;
import com.itheima.bean.DishFlavor;
import com.itheima.common.R;
import com.itheima.dto.DishDto;
import com.itheima.exception.CustomException;
import com.itheima.service.CategoryService;
import com.itheima.service.DishFlavorService;
import com.itheima.service.DishService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.bind.annotation.*;

import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Slf4j
@RequestMapping("/dish")
@RestController
public class DishController {

    @Autowired
    private DishService dishService;

    @Autowired
    private CategoryService categoryService;

    @Autowired
    private DishFlavorService dishFlavorService;

    @Autowired
    private RedisTemplate redisTemplate;

    //新增菜品
    @PostMapping
    public R<String> add(@RequestBody DishDto dishDto) {
        //1.调用service处理
        dishService.saveWithFlavor(dishDto);

        //声明redis中key的名称
        String key = "dish_" + dishDto.getCategoryId() + "_" + dishDto.getStatus();

        //删除redis存储的数据
        redisTemplate.delete(key);

        //2.响应数据
        return R.success("新增成功！");
    }

    //分页查询
    @GetMapping("/page")
    public R<Page<DishDto>> findPage(@RequestParam(defaultValue = "1") Integer page, @RequestParam(defaultValue = "10") Integer pageSize, String name) {
        //前提工作：配置MyBatisPlus分页拦截器
        //1.接收请求参数
        //2.调用service处理  由于当前功能比较简单，可以直接使用MyBatisPlus在service层提供的通用方法page()完成
        //2.1：创建page对象封装分页参数 当前页码page、每页显示条数pageSize
        Page<Dish> dishPage = new Page<>(page, pageSize);

        //2.2：创建LambdaQueryWrapper对象 封装查询条件 员工姓名name 注意：添加null值处理
        LambdaQueryWrapper<Dish> wrapper = new LambdaQueryWrapper<>();
        wrapper.like(name != null && name.length() > 0, Dish::getName, name);

        //2.3：调用service中page方法 查询得到分页数据
        dishService.page(dishPage, wrapper);
        log.info("【employeePage：{}】", dishPage);



        /*
            细节：菜品分类没有展示出来
            分析：
                1.因为当前我们响应给前端页面的数据  Page<Dish> dishPage
                2.当前页的数据 List<Dish> records = dishPage.getRecords();
                3.当前页数据 每一条记录都是dish对象  而在dish对象中
                4.dish对象中只有菜品所属分类id 没有所属分类名称
            解决：
                1.需要根据每一个菜品所属分类id查询出所属分类名称
                2.响应给前端页面展示的每一条菜品数据中应该都包含 菜品所属分类名称字段
                3.由于Dish对象中没有品所属分类名称字段  所以这里就需要使用DishDto存储菜品的基本信息和所属分类名称
                4.我们应该响应给页面的当前页数据应该是一个 List<DishDto>集合
                5.最终 应该响应给页面的是Page<DishDto>：records、total records存放当前页数据集合 List<DishDto> total存放总条数
            实现步骤：
                1.创建一个Page<DishDto>对象
                2.将Page<Dish>对象中的所有属性数据除了records 都复制到Page<DishDto>对象属性上
                3.从Page<Dish>对象中得到当前页数据List<Dish>集合
                4.将List<Dish>集合 中的数据封装到  List<DishDto>集合中 需要根据菜品分类id查询分类名称封装到DishDto对象中
                5.手动设置Page<DishDto>对象的records属性值为List<DishDto>集合
                6.修改方法的返回值为Page<DishDto>

            数据封装流程：
                1.Page<Dish>-->Page<DishDto>
                2.List<Dish>-->List<DishDto>
                3.dish      --> dishDto
         */

        //1.创建一个Page<DishDto>对象
        Page<DishDto> dishDtoPage = new Page<>();

        //2.将Page<Dish>对象中的所有属性数据除了records 都复制到Page<DishDto>对象属性上
        //Spring框架的中的工具类 将一个对象的属性属性复制到另一个对象的属性上  要求源对象和目标对象属性名称一致
        BeanUtils.copyProperties(dishPage, dishDtoPage, "records");

        //3.从Page<Dish>对象中得到当前页数据List<Dish>集合
        List<Dish> dishList = dishPage.getRecords();

        //4.将List<Dish>集合 中的数据封装到  List<DishDto>集合中 需要根据菜品分类id查询分类名称封装到DishDto对象中
        List<DishDto> dishDtoList = new ArrayList<>();
        for (Dish dish : dishList) {
            DishDto dishDto = new DishDto();
            //4.1：将菜品基本信息封装到DishDto对象中
            BeanUtils.copyProperties(dish, dishDto);
            //4.2：根据当前菜品所属分类id查询分类名称
            Category category = categoryService.getById(dish.getCategoryId());
            dishDto.setCategoryName(category == null ? "未知类型" : category.getName());
            //4.3：将dishDto对象放入到List<DishDto>集合中
            dishDtoList.add(dishDto);
        }

        //5.手动设置Page<DishDto>对象的records属性值为List<DishDto>集合
        dishDtoPage.setRecords(dishDtoList);

        //6.修改方法的返回值为Page<DishDto>

        //3.响应json数据  将分页数据封装到R对象中统一格式返回
        return R.success(dishDtoPage);
    }

    //数据回显--根据id查询菜品及其口味信息
    @GetMapping("/{id}")
    public R<DishDto> findById(@PathVariable Long id) {
        //1.调用service处理 得到DishDto对象
        DishDto dishDto = dishService.findById(id);

        //2.响应数据
        return R.success(dishDto);
    }

    //保存修改后的菜品信息
    @PutMapping
    public R<String> update(@RequestBody DishDto dishDto) {
        //优化菜品修改 缓存数据
        //先查询修改前的菜品分类id
        Long oldCategoryId = dishService.getById(dishDto.getId()).getCategoryId();
        //声明redis中key的名称
        String key = "dish_" + oldCategoryId + "_1";
        //删除修改前所属分类的id的redis缓存数据
        redisTemplate.delete(key);

        //1.调用service处理
        dishService.updateWithFlavor(dishDto);

        //获得修改后的菜品分类id
        Long newcategoryId = dishDto.getCategoryId();
        //判断修改前后修改后的分类id是否相等 不相等删除修改后的redis缓存中所属分类id的数据
        if (!oldCategoryId.equals(newcategoryId)) {
            key = "dish_" + newcategoryId + "_1";
            redisTemplate.delete(key);
        }

        //2.响应数据
        return R.success("修改成功！");
    }

    //根据菜品分类id和菜品名称查询菜品列表数据
    @GetMapping("/list")
    public R<List<DishDto>> list(Dish dish) {

        //声明redis中key的名称
        String key = "dish_" + dish.getCategoryId() + "_" + dish.getStatus();

        //判断redis中key是否存在 存在从redis中读取  在redis中存储的对象是json格式
        if (redisTemplate.hasKey(key)) {
            log.info("从redis读取数据");
            String jsonStr = (String) redisTemplate.opsForValue().get(key);
            List<DishDto> list = JSON.parseObject(jsonStr, List.class);
            return R.success(list);
        }

        log.info("从MySQL读取数据");
        //1.调用service处理，得到菜品列表数据
        //1.1：创建wrapper对象
        LambdaQueryWrapper<Dish> wrapper = new LambdaQueryWrapper<>();

        //1.2：设置查询条件    【菜品所属分类id、菜品名称、菜品状态status】
        wrapper.eq(dish.getCategoryId() != null, Dish::getCategoryId, dish.getCategoryId()); //当分类id不为null 根据分类id进行查询
        wrapper.like(dish.getName() != null, Dish::getName, dish.getName());    //当菜品名称name不为null，根据菜品名称进行模糊查询

        /*=======1.添加查询条件  当status不为null时，设置查询启售的菜品列表数据======**/
        wrapper.eq(dish.getStatus() != null, Dish::getStatus, dish.getStatus());  //查询启售的菜品

        //1.3：调用list方法查询
        List<Dish> list = dishService.list(wrapper);

        /*=======3.循环遍历List<Dish>集合，将菜品的基本信息封装到DishDto对象中======**/
        List<DishDto> dishDtoList = list.stream().map((item) -> {
            DishDto dishDto = new DishDto();
            BeanUtils.copyProperties(item, dishDto);
            /*=======4.还需要根据菜品的分类id和菜品id查询出所属分类名称和菜品的口味信息封装到DishDto对象中======**/
            Category category = categoryService.getById(item.getCategoryId());
            dishDto.setCategoryName(category == null ? "未知" : category.getName());

            LambdaQueryWrapper<DishFlavor> wrapper1 = new LambdaQueryWrapper<>();
            wrapper1.eq(DishFlavor::getDishId, item.getId());
            List<DishFlavor> flavors = dishFlavorService.list(wrapper1);
            dishDto.setFlavors(flavors);
            return dishDto;
        }).collect(Collectors.toList());


        /*=======5.将DishDto存入到List集合中 返回======**/
        //2.响应数据
        //在redis不存在将查询到的结果存储到redis
        String jsonString = JSON.toJSONString(dishDtoList);
        redisTemplate.opsForValue().set(key, jsonString, 24, TimeUnit.HOURS);
        return R.success(dishDtoList);
    }

    //根据菜品id删除|批量删除
    @DeleteMapping()
    public R<String> delete(Long[] ids) {

        //根据id查询数据库获得分类的id 存储到set集合
        List<Dish> dishList = dishService.listByIds(Arrays.asList(ids));
        Set<Long> categoryIds = new HashSet<>();
        dishList.stream().forEach(dish -> {
            Long categoryId = dish.getCategoryId();
            categoryIds.add(categoryId);
        });

        // 1.调用service
        boolean flag = dishService.deleteByIds(ids);

        //删除成功 ,删除redis中所属分类id的数据
        for (Long categoryId : categoryIds) {
            String key = "dish_" + categoryId + "_1" ;
            redisTemplate.delete(key);
        }

        // 2.响应数据
        return flag ? R.success("删除成功") : R.error("删除失败");
    }

    //停售启售|批量停售启售
    @PostMapping("/status/{status}")
    public R<String> changeStatus(Long[] ids, @PathVariable Integer status) {
        // 调用service
        dishService.changeStatusByIds(ids, status);
        // 响应数据
        return R.success("修改成功");
    }

}
